﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Xml.Serialization;

namespace VersionComparer.DataModel
{
    [Serializable]
    public class ItemNamePairList
    {
        #region statics
        public static string[] ItemsToStrings(ItemId[] list)
        {
            if ( list == null )
                return new string[0];
            string[] aux = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
                aux[i] = list[i].Name;
            return aux;
        }
        public static ItemId[] StringsToItems(string[] list)
        {
            if (list == null)
                return new ItemId[0];
            ItemId[] aux = new ItemId[list.Length];
            for (int i = 0; i < list.Length; i++)
                aux[i] = new ItemId(list[i]);
            return aux;
        }
        public static string ListToText(string[] list)
        {
            return ListToText(StringsToItems(list));
        }
        public static string ListToText(ItemId[] list)
        {
            if (list == null)
                return null;

            StringBuilder builder = new StringBuilder();
            foreach (ItemId file in list)
                builder.AppendFormat("{0};", file.Name);
            return builder.ToString().Trim(';');
        }
        public static string[] TextToList(string text)
        {
            if (text == null)
                return new string[0];
            return text.Split("\r\n;|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

        }
        #endregion statics

        #region fields
        string name1;
        string name2;
        string name;
        
        List<ItemNamePair> list = new List<ItemNamePair>();
        
        [NonSerialized]
        ExclusionRules rules;
        #endregion fields

        #region constructors

        public ItemNamePairList()
        {
            
            ExplicitlyCreated = false;
            Name = "";
            LastUsed = DateTime.Now;
        }
        public ItemNamePairList(ItemId[] items1, ItemId[] items2)
            : this()
        {
            Set(Name , items1, items2);
        }
        #endregion constructors

        #region properties
        public ItemId[] Items1
        {
            get
            {
                List<ItemId> items = new List<ItemId>();
                foreach (ItemNamePair itemPair in list)
                    items.Add(itemPair.Item1);
                return items.ToArray();
            }
        }
        public ItemId[] Items2
        {
            get
            {
                List<ItemId> items = new List<ItemId>();
                foreach (ItemNamePair itemPair in list)
                    items.Add(itemPair.Item2);
                return items.ToArray();
            }
        }
        public int Count
        {
            get
            {
                return Math.Max(Items1.Length, Items2.Length);
            }
        }

        public string Name1
        {
            get
            {
                if (name1 == null)
                {
                    if (ExplicitlyCreated)
                        name1 = string.Format("<{0}>", Name);
                    else
                        name1 = ListToText(Items1);
                }
                return name1;
            }
        }
        public string Name2
        {
            get
            {
                if (name2 == null)
                {
                    if (ExplicitlyCreated)
                        name2 = string.Format("<{0}>", Name);
                    else
                        name2 = ListToText(Items2);
                }
                return name2;
            }
        }

        [XmlIgnore]
        public ItemNamePairLists Owner
        {
            get;
            set;
        }
        [XmlElement]
        public ExclusionRules Rules
        {
            get
            {
                if (rules == null)
                    rules = new ExclusionRules(this);
                return rules;
            }
            set
            {
                rules = value;
                rules.OwnerList = this;
            }

        }
        bool explicitlyCreated;
        [XmlElement]
        public bool ExplicitlyCreated 
        {
            get
            {
                return explicitlyCreated;
            }
            set
            {
                explicitlyCreated = value;
                name1 = null;
                name2 = null;
            }
        }

        [XmlElement]
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
                name1 = null;
                name2 = null;
            }
        }
        [XmlElement]
        public DateTime LastUsed
        {
            get;
            set;
        }
        [XmlElement]
        public List<ItemNamePair> List
        {
            get
            {
                return list;
            }
            private set
            {
                name1 = null;
                name2 = null;
                list = value;
            }
        }
        #endregion properties

        public void Set(string name, string[] items1, string[] items2)
        {
            if (items1 == null)
                items1 = new string[0];
            if (items2 == null)
                items2 = new string[0];
            ItemId[] aux1 = new ItemId[items1.Length];
            ItemId[] aux2 = new ItemId[items2.Length];
            for (int i = 0; i < items1.Length; i++)
                aux1[i] = new ItemId(items1[i]);
            for (int i = 0; i < items2.Length; i++)
                aux2[i] = new ItemId(items2[i]);
            Set(name, aux1, aux2);
        }
        public void Set(string name, ItemId[] items1, ItemId[] items2)
        {
            list.Clear();

            if (Name != name && !string.IsNullOrEmpty (name))
            {
                Name = name;
                ExplicitlyCreated = true;
            }
            if ( items1 == null )
                items1 = new ItemId[0];
            if ( items2 == null )
                items2 = new ItemId[0];

            for (int i = 0; i < items1.Length || i < items2.Length; i++)
            {
                ItemId item1 = i < items1.Length ? items1[i] : ItemId.CreateEmpty();
                ItemId item2 = i < items2.Length ? items2[i] : ItemId.CreateEmpty();
                if (item1 == null)
                    item1 = ItemId.CreateEmpty();
                if (item2 == null)
                    item2 = ItemId.CreateEmpty();
                list.Add(new ItemNamePair()
                    {
                        Item1 = item1,
                        Item2 = item2
                    });
            }

            for (int i = list.Count - 1; i >= 0; i--)
                if (list[i].Item1.IsEmpty && list[i].Item1.IsEmpty)
                    list.RemoveAt(i);
            name1 = null;
            name2 = null;
        }
        public void Add(ItemId[] items1)
        {
            if (items1 == null || items1.Length == 0)
                return;
            List<ItemId> newItems1 = new List<ItemId>();
            newItems1.AddRange(Items1);
            newItems1.AddRange(items1);
            List<ItemId> newItems2 = new List<ItemId>();
            newItems2.AddRange(Items2);
            ItemId[] aux = new ItemId[items1.Length];
            for (int i = 0; i < aux.Length; i++)
                aux[i] = new ItemId ("");
            newItems2.AddRange(aux);
            Set(Name, newItems1.ToArray(), newItems2.ToArray());
        }
        public void Add(string[] items1)
        {
            if  (items1 == null || items1.Length == 0)
                return;
            ItemId[] aux = new ItemId[items1.Length];
            for (int i = 0; i < items1.Length; i++)
                aux[i] = new ItemId(items1[i]);
            Add(aux);
        }
        public void AddItems2(ItemId[] items2)
        {
            if (items2 == null || items2.Length == 0)
                return;

            List<ItemId> newItems2 = new List<ItemId>(Items2);

            int lastEmpty;
            for (lastEmpty = newItems2.Count - 1; lastEmpty >= 0; lastEmpty--)
            {
                if (!Items2[lastEmpty].IsEmpty)
                {
                    lastEmpty++;
                    break;
                }
            }
            if (lastEmpty < 0)
                lastEmpty = 0;

            int j, i;
            for (i =lastEmpty , j = 0; i < newItems2.Count && j < items2.Length; i++,j++ )
                newItems2[i].Name = items2[j].Name;

            List<ItemId> newItems1 = new List<ItemId>(Items1);
            for (; j < items2.Length; j++)
            {
                newItems1.Add( ItemId.CreateEmpty());
                newItems1.Add(items2[j]);
            }
            Set(Name, newItems1.ToArray(), newItems2.ToArray());

        }
        public bool Remove(string name1, string name2)
        {
            return Remove(new ItemId[] { new ItemId(name1) }, new ItemId[] { new ItemId(name2 )});
        }
        public bool Remove(ItemId[] name1, ItemId[] name2)
        {
            if ( name2 == null || name1 == null )
                return false;
            List<ItemId> items1 = new List<ItemId>(Items1);
            List<ItemId> items2 = new List<ItemId>(Items2);
            bool changed = false;
            //not very performant, but it should do for the average-to-big list
            for (int i = 0; i < items1.Count && i < items2.Count; i++)
            {
                for (int j = 0; j < name1.Length && j < name2.Length; j++)
                {
                    if (items1[i] == name1[j] && items2[i] == name2[j])
                    {
                        changed = true;
                        items1.RemoveAt(i);
                        items2.RemoveAt(i);
                        i--;
                        break;
                    }
                }
            }
            if (changed)
            {
                Set(Name, items1.ToArray(), items2.ToArray());
                Save();
            }
            return changed;
        }
        public void Save()
        {
            if ( Owner != null )
                Owner.Save();
        }
        
        public override string ToString()
        {
            return Name;
        }
        private bool CompareList(ItemId[] items1, ItemId[] items2)
        {
            if (items1 == null)
                items1 = new ItemId[0];
            if (items2 == null)
                items2 = new ItemId[0];

            if (items1.Length != items2.Length)
                return false;
            for (int i = 0; i < items1.Length; i++)
                if (items1[i].Name != items2[i].Name)
                    return false;
            
            return true;
        }
        public bool IsEqualTo(ItemId[] items1, ItemId[] items2)
        {
            return CompareList(items1, Items1) && CompareList(items2, Items2);
        }
        public ItemNamePairList Clone()
        {
            ItemNamePairList newlist = new ItemNamePairList();
            newlist.Set(Name, Items1, Items2);
            return newlist;
        }
    }
}
